<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>执行上下文与执行上下文栈</title>
  </head>
  <body>
    <script>
      /**
       * 1. 代码分类(位置)
       *    全局代码
       *    函数代码
       * 2. 全局执行上下文
       *    在执行全局代码前将window确定为全局执行上下文
       *    对全局数据进行预处理
       *    var定义的全局变量==>undefined, 添加为window的属性
       *    function声明的全局函数==>赋值(fun), 添加为window的方法
       *    this==>赋值(window)
       *    开始执行全局代码
       * 3. 函数执行上下文
       *    在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象
       *    对局部数据进行预处理
       *    形参变量==>赋值(实参)==>添加为执行上下文的属性
       *    arguments==>赋值(实参列表), 添加为执行上下文的属性
       *    var定义的局部变量==>undefined, 添加为执行上下文的属性
       *    function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
       *    this==>赋值(调用函数的对象)
       *    开始执行函数体代码
       * */
      console.log(a1, window.a1);
      console.log(window.a2);
      console.log(this);
      var a1 = 3;
      function a2() {
        console.log("a2()");
      }

      console.log("-----------------------");

      //函数执行上下文
      function fn(a1) {
        console.log(a1); //2
        console.log(a2); //undefined
        a3(); //a3()
        console.log(this); //window
        console.log(arguments); //伪数组
        var a2 = 3;
        function a3() {
          console.log("a3()");
        }
      }
      fn(2, 3);
    </script>

    <script>
      // 1.进入全局执行上下文
      /**
       * 4.执行上下文栈
       *   步骤1：在全局代码执行前，JS引擎就会创建一个栈来存储管理所有的上下文对象
       *   步骤2：在全局执行上下文(window)确定后，将其添加到栈中(压栈)
       *   步骤3：在函数执行上下文创建后，将其添加到栈中(压栈)
       *   步骤4：在当前函数执行完后，将其栈顶的对象移除(出栈)
       *   步骤5：当所有的代码执行完后，栈中只剩下window
       * */
      var a = 10;
      var bar = function (x) {
        var b = 5;
        foo(x + b); // 3.进入foo执行上下文
      };

      var foo = function (y) {
        var c = 5;
        console.log(a + c + y);
      };
      bar(10); // 2.进入bar函数执行上下文
    </script>

    <script>
      /**
       * 面试题1：先执行变量提升，再执行函数提升
       * */
      function a4() {}
      var a4;
      console.log(typeof a4); //function

      /**
       * 面试题2
       * */
      if (!(b in window)) {
        var b = 1;
      }
      console.log(b); // undefined
    </script>
  </body>
</html>
